package com.partsoft.dits.log;



import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import com.partsoft.dits.DataChangeLog;
import com.partsoft.dits.DataEdgeDescriptor;
import com.partsoft.dits.integrate.IdNumericDataChangeLog;
import com.partsoft.dits.message.DataAction;
import com.partsoft.dits.utils.DbUtils;
import com.partsoft.dits.utils.ExecutionCallback;
import com.partsoft.dits.utils.JdbcTemplate;
import com.partsoft.dits.utils.ReturnExecutionCallback;

/**
 * JDBC数据变更日志存储器
 */
public abstract class AbstractJdbcDataChangeLogStorage implements InitializingBean, ChangeLogResolver, ChangeLogStorage {

	/**
	 * 缺省的创建表的SQL
	 */
	protected static final String Default_CreateStorageJdbcSQL_Template = "CREATE TABLE %s ( SID BIGINT  NOT NULL  GENERATED ALWAYS AS IDENTITY (START WITH 0, INCREMENT BY 1, NO CACHE ) , SCODE VARCHAR (32) , SDESC VARCHAR (128), DESCID VARCHAR (128)  , SKEY VARCHAR (256)  NOT NULL , CTPE SMALLINT  NOT NULL , UPTM TIMESTAMP  NOT NULL, CONSTRAINT %s PRIMARY KEY (SID))";

	/**
	 * 缺省的插入日志的SQL
	 */
	protected static final String Default_SaveLogJdbcSQL_Template = "INSERT INTO %s(SCODE,SDESC,DESCID,SKEY,CTPE,UPTM) VALUES(?, ?, ?, ?, ?, ?)";

	/**
	 * 缺省的获得最后更新记录的SQL
	 */
	protected static final String Default_GetLastLogJdbcSQL_Template = "SELECT * FROM %s WHERE SCODE=? AND SDESC=? AND DESCID=? %s ORDER BY SID DESC FETCH FIRST 1 ROWS ONLY";

	/**
	 * 缺省的返回SKEY对应SID的SQL
	 */
	protected static final String Default_GetIdEQChangeLogSQL_Template = "SELECT SID FROM %s WHERE SCODE=? AND SDESC=? and DESCID=? and SKEY=? and CTPE=? and UPTM=? ORDER BY SID DESC FETCH FIRST 1 ROWS ONLY";

	/**
	 * 缺省的返回最后变更的SKEY对应的SQL
	 */
	protected static final String Default_GetLastChangeLogIdSQL_Template = "SELECT SID FROM %s WHERE SCODE=? AND SDESC=? and DESCID=? and SKEY=? ORDER BY SID DESC FETCH FIRST 1 ROWS ONLY";

	/**
	 * 缺省的返回大于某ID的SQL
	 */
	protected static final String Default_GetIdGtChangeLogSQL_Template = "SELECT * FROM %s WHERE SCODE=? AND SDESC=? and DESCID in (%s) AND SID > ? %s ORDER BY SID";

	protected static final String Default_CountIdGtChangeLogSQL_Template = "SELECT COUNT(SID) FROM %s WHERE SCODE=? AND SDESC=? and DESCID in (%s) AND SID > ? %s";

	private String namespace;

	/**
	 * 创建表的SQL
	 */
	private String createStorageJdbcSQLTemplate = Default_CreateStorageJdbcSQL_Template;

	/**
	 * 插入日志的SQL
	 */
	private String saveLogJdbcSQLTemplate = Default_SaveLogJdbcSQL_Template;

	/**
	 * 获得最后更新记录的SQL
	 */
	private String lastLogJdbcSQLTemplate = Default_GetLastLogJdbcSQL_Template;

	/**
	 * 返回SKEY对应SID的SQL
	 */
	private String idEQChangeLogSQLTemplate = Default_GetIdEQChangeLogSQL_Template;

	/**
	 * 返回大于某ID的SQL
	 */
	private String idGtChangeLogSQLTemplate = Default_GetIdGtChangeLogSQL_Template;

	private String lastChangeLogIdSQLTemplate = Default_GetLastChangeLogIdSQL_Template;

	private String countIdGtChangeLogSQLTemplate = Default_CountIdGtChangeLogSQL_Template;

	/**
	 * 模式名称
	 */
	private String tableSchemaName = "DITS";

	/**
	 * 表名
	 */
	private String tableName = "DATA_CHANGE_LOG_HISTORY";

	public void setNamespace(String namespace) {
		this.namespace = namespace;
	}

	public String getNamespace() {
		return namespace == null ? "" : namespace;
	}

	protected String getTableSchemaName() {
		return tableSchemaName;
	}

	public void setTableSchemaName(String tableSchemaName) {
		this.tableSchemaName = tableSchemaName;
	}

	protected String getTableFullName() {
		return DbUtils.packSchemaTableName(getTableSchemaName(), getTableName());
	}

	protected String getTableName() {
		return tableName;
	}

	public void setTableName(String tableName) {
		this.tableName = tableName;
	}

	protected String getCreateStorageJdbcSQLTemplate() {
		return createStorageJdbcSQLTemplate;
	}

	public void setCreateStorageJdbcSQLTemplate(String createStorageJdbcSQLTemplate) {
		this.createStorageJdbcSQLTemplate = createStorageJdbcSQLTemplate;
	}

	protected String getSaveLogJdbcSQLTemplate() {
		return saveLogJdbcSQLTemplate;
	}

	public void setSaveLogJdbcSQLTemplate(String saveLogJdbcSQLTemplate) {
		this.saveLogJdbcSQLTemplate = saveLogJdbcSQLTemplate;
	}

	protected String getLastLogJdbcSQLTemplate() {
		return lastLogJdbcSQLTemplate;
	}

	public void setLastLogJdbcSQLTemplate(String lastLogJdbcSQLTemplate) {
		this.lastLogJdbcSQLTemplate = lastLogJdbcSQLTemplate;
	}

	protected String getIdEQChangeLogSQLTemplate() {
		return idEQChangeLogSQLTemplate;
	}

	public void setIdEQChangeLogSQLTemplate(String idEQChangeLogSQLTemplate) {
		this.idEQChangeLogSQLTemplate = idEQChangeLogSQLTemplate;
	}

	protected String getIdGtChangeLogSQLTemplate() {
		return idGtChangeLogSQLTemplate;
	}

	public void setIdGtChangeLogSQLTemplate(String idGtChangeLogSQLTemplate) {
		this.idGtChangeLogSQLTemplate = idGtChangeLogSQLTemplate;
	}

	protected String getLastChangeLogIdSQLTemplate() {
		return lastChangeLogIdSQLTemplate;
	}

	public void setLastChangeLogIdSQLTemplate(String lastChangeLogIdSQLTemplate) {
		this.lastChangeLogIdSQLTemplate = lastChangeLogIdSQLTemplate;
	}

	protected String getCountIdGtChangeLogSQLTemplate() {
		return countIdGtChangeLogSQLTemplate;
	}

	public void setCountIdGtChangeLogSQLTemplate(String countIdGtChangeLogSQLTemplate) {
		this.countIdGtChangeLogSQLTemplate = countIdGtChangeLogSQLTemplate;
	}

	protected abstract DataSource resolveJdbcDataSource();

	protected String buildLastLogJdbcSQL(String dataIdentityPrefix) {
		// SELECT * FROM %s WHERE SCODE=? AND SDESC=? AND DESCID=? ORDER BY
		// UPTM DESC FETCH FIRST 1 ROWS ONLY
		StringBuffer sbf = new StringBuffer();
		if (StringUtils.hasText(dataIdentityPrefix)) {
			sbf.append("AND SKEY LIKE '").append(dataIdentityPrefix).append("%'");
		}
		return String.format(getLastLogJdbcSQLTemplate(), getTableFullName(), sbf.toString());
	}

	protected String buildSaveLogJdbcSQL() {
		// INSERT INTO %s(SCODE,SDESC,DESCID,SKEY,CTPE,UPTM) VALUES(?, ?, ?, ?,
		// ?, ?)
		return String.format(getSaveLogJdbcSQLTemplate(), getTableFullName());
	}

	protected String buildCreateStorageJdbcSQL() {
		// CREATE TABLE %s ( SID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY
		// (START WITH 0, INCREMENT BY 1, NO CACHE ) , SCODE VARCHAR (32) ,
		// SDESC VARCHAR (128), DESCID VARCHAR (128) , SKEY VARCHAR (96) NOT
		// NULL , CTPE SMALLINT NOT NULL , UPTM TIMESTAMP NOT NULL, CONSTRAINT
		// %s PRIMARY KEY (SID))
		return String.format(getCreateStorageJdbcSQLTemplate(), getTableFullName(), new StringBuilder(
				getTableSchemaName()).append("_").append(getTableName()).append("_PKEY").toString());
	}

	protected String buildIdEQChangeLogSQL() {
		// SELECT SID FROM %s WHERE SCODE=? AND SDESC=? and DESCID=? and SKEY=?
		// and CTPE=? and UPTM=? ORDER BY UPTM DESC FETCH FIRST 1 ROWS ONLY
		return String.format(getIdEQChangeLogSQLTemplate(), getTableFullName());
	}

	protected String buildIdGtChangeLogSQL(String dataIdentityPrefix, int idCount) {
		// SELECT * FROM %s WHERE SCODE=? AND SDESC=? and DESCID in (%s) AND SID
		// > ?
		// ORDER BY UPTM
		boolean append = false;
		StringBuffer tsfBuffer = new StringBuffer(15);
		for (int i = 0; i < idCount; i++) {
			if (append)
				tsfBuffer.append(", ");
			tsfBuffer.append("?");
			append = true;
		}
		StringBuffer sKeyBuf = new StringBuffer();
		if (StringUtils.hasText(dataIdentityPrefix)) {
			sKeyBuf.append("AND SKEY LIKE '").append(dataIdentityPrefix).append("%'");
		}
		return String.format(getIdGtChangeLogSQLTemplate(), getTableFullName(), tsfBuffer.toString(),
				sKeyBuf.toString());
	}

	protected String buildLastChangeLogIdSQL() {
		return String.format(getLastChangeLogIdSQLTemplate(), getTableFullName());
	}

	protected String buildCountIdGtChangeLog(String dataIdentityPrefix, int idCount) {
		boolean append = false;
		StringBuffer tsfBuffer = new StringBuffer(15);
		for (int i = 0; i < idCount; i++) {
			if (append)
				tsfBuffer.append(", ");
			tsfBuffer.append("?");
			append = true;
		}
		StringBuffer sKeyBuffer = new StringBuffer();
		if (StringUtils.hasText(dataIdentityPrefix)) {
			sKeyBuffer.append(" AND SKEY LIKE '").append(dataIdentityPrefix).append("%' ");
		}
		return String.format(getCountIdGtChangeLogSQLTemplate(), getTableFullName(), tsfBuffer.toString(),
				sKeyBuffer.toString());
	}

	protected void doCreateStorageTable() {
		final String extSQL = buildCreateStorageJdbcSQL();
		DataSource ds = resolveJdbcDataSource();
		final JdbcTemplate jdbcHelper = new JdbcTemplate(ds);
		DbUtils.executeInTransaction(ds, TransactionAttribute.PROPAGATION_REQUIRED, new ExecutionCallback() {
			public void callback() {
				jdbcHelper.update(extSQL);
			}
		});
	}

	protected Date doSaveChangeLogReturnRecordTime(final DataEdgeDescriptor dataDesc, final String id,
			final DataAction action) {
		Assert.notNull(dataDesc);
		Assert.hasText(id);
		Assert.notNull(action);
		final String extSQL = buildSaveLogJdbcSQL();
		DataSource ds = resolveJdbcDataSource();
		final JdbcTemplate jdbcHelper = new JdbcTemplate(ds);
		final Date recordDate = new Date();
		final String sKey = StringUtils.hasText(dataDesc.getDataIdentityPrefix()) ? dataDesc.getDataIdentityPrefix()
				+ id : id;
		DbUtils.executeInTransaction(ds, TransactionAttribute.PROPAGATION_REQUIRED, new ExecutionCallback() {
			public void callback() {
				jdbcHelper.update(extSQL, getNamespace(), ClassUtils.getUserClass(dataDesc).getName(),
						dataDesc.getId(), sKey, action.getCode(), recordDate);
			}
		});
		return recordDate;
	}

	protected long doSaveChangeLog(DataEdgeDescriptor dataDesc, String id, DataAction action) {
		return doGetChangeLogId(dataDesc, id, action, doSaveChangeLogReturnRecordTime(dataDesc, id, action));
	}

	protected long doGetLastChangeLogId(final DataEdgeDescriptor dataDesc, final String skey) {
		Assert.notNull(dataDesc);
		Assert.hasText(skey);
		final String extSQL = buildLastChangeLogIdSQL();
		DataSource ds = resolveJdbcDataSource();
		final JdbcTemplate jdbcHelper = new JdbcTemplate(ds);

		return DbUtils.executeInReadonly(ds, new ReturnExecutionCallback<Long>() {
			public Long callback() {
				try {
					return jdbcHelper.queryForLong(extSQL, getNamespace(), ClassUtils.getUserClass(dataDesc).getName(),
							dataDesc.getId(), skey);
				} catch (EmptyResultDataAccessException e) {
					return 0L;
				}
			}
		});
	}

	protected long doGetChangeLogId(final DataEdgeDescriptor dataDesc, final String id, final DataAction action,
			final Date date) {
		Assert.notNull(dataDesc);
		Assert.hasText(id);
		Assert.notNull(action);
		final String extSQL = buildIdEQChangeLogSQL();
		DataSource ds = resolveJdbcDataSource();
		final JdbcTemplate jdbcHelper = new JdbcTemplate(ds);
		final String sKey = StringUtils.hasText(dataDesc.getDataIdentityPrefix()) ? dataDesc.getDataIdentityPrefix()
				+ id : id;
		return DbUtils.executeInReadonly(ds, new ReturnExecutionCallback<Long>() {
			public Long callback() {
				try {
					return jdbcHelper.queryForLong(extSQL, getNamespace(), ClassUtils.getUserClass(dataDesc).getName(),
							dataDesc.getId(), sKey, action.getCode(), date);
				} catch (EmptyResultDataAccessException e) {
					return 0L;
				}
			}
		});
	}

	private DataChangeLog doGetLastChangeLogOne(final DataSource ds, final JdbcTemplate jdbcHelper,
			final String extSQL, final String descriptorClazzName, final String descriptorId) {
		return DbUtils.executeInReadonly(ds, new ReturnExecutionCallback<DataChangeLog>() {
			public DataChangeLog callback() {
				List<DataChangeLog> queryList = jdbcHelper.query(extSQL, new Object[] { getNamespace(),
						descriptorClazzName, descriptorId }, DataChangeLogMapper.INST);
				return queryList.size() > 0 ? queryList.get(0) : null;
			}
		});
	}

	protected DataChangeLog doGetLastChangeLog(DataEdgeDescriptor dataDesc) {
		DataSource ds = resolveJdbcDataSource();
		String descriptorClazzName = dataDesc == null ? "" : ClassUtils.getUserClass(dataDesc).getName();
		String descriptorIds = dataDesc == null ? "" : StringUtils.hasText(dataDesc.getId()) ? dataDesc.getId() : "";
		String splets[] = descriptorIds.split(";");
		JdbcTemplate jdbcHelper = new JdbcTemplate(ds);
		final String extSQL = buildLastLogJdbcSQL(dataDesc.getDataIdentityPrefix());
		DataChangeLog resultChangeLog = doGetLastChangeLogOne(ds, jdbcHelper, extSQL, descriptorClazzName, splets[0]);

		if (splets.length > 1) {
			for (int i = 1; i < splets.length; i++) {
				DataChangeLog changeLog = doGetLastChangeLogOne(ds, jdbcHelper, extSQL, descriptorClazzName, splets[i]);
				if (resultChangeLog != null) {
					if (changeLog != null) {
						int changeLogId = Integer.valueOf(changeLog.getId());
						int oldLogId = Integer.valueOf(resultChangeLog.getId());
						if (changeLogId > oldLogId) {
							resultChangeLog = changeLog;
						}
					}
				} else {
					resultChangeLog = changeLog;
				}
			}
		}

		return resultChangeLog;

	}

	private List<DataChangeLog> doGetChangeLogGreaterThanIdOne(final DataSource ds, final JdbcTemplate jdbcHelper,
			final String extSQL, final List<Object> params) {

		return DbUtils.executeInReadonly(ds, new ReturnExecutionCallback<List<DataChangeLog>>() {
			public List<DataChangeLog> callback() {
				return jdbcHelper.query(extSQL, params.toArray(new Object[0]), DataChangeLogMapper.INST);
			}
		});
	}

	protected List<DataChangeLog> doGetChangeLogGreaterThanId(DataEdgeDescriptor dataDesc, long id) {
		DataSource ds = resolveJdbcDataSource();
		String descriptorClazzName = dataDesc == null ? "" : ClassUtils.getUserClass(dataDesc).getName();
		String descriptorIds = dataDesc == null ? "" : StringUtils.hasText(dataDesc.getId()) ? dataDesc.getId() : "";
		String splets[] = descriptorIds.split(";");
		JdbcTemplate jdbcHelper = new JdbcTemplate(ds);
		// List<DataChangeLog> resultList = new LinkedList<DataChangeLog>();
		String extSQL = buildIdGtChangeLogSQL(dataDesc.getDataIdentityPrefix(), splets.length);
		List<Object> parameters = new ArrayList<Object>(3 + splets.length);
		parameters.add(getNamespace());
		parameters.add(descriptorClazzName);
		parameters.addAll(Arrays.asList(splets));
		parameters.add(id);
		return doGetChangeLogGreaterThanIdOne(ds, jdbcHelper, extSQL, parameters);
		// resultList.addAll(doGetChangeLogGreaterThanIdOne(ds, jdbcHelper,
		// extSQL, descriptorClazzName, splets[0], id));
		// if (splets.length > 1) {
		// for (int i = 1; i < splets.length; i++) {
		// resultList.addAll(doGetChangeLogGreaterThanIdOne(ds, jdbcHelper,
		// extSQL, descriptorClazzName, splets[i], id));
		// }
		// }
		// return resultList;
	}

	private int doCountChangeLogGreaterThanIdOne(final DataSource ds, final JdbcTemplate jdbcHelper,
			final String extSQL, final List<Object> parameters) {
		return DbUtils.executeInReadonly(ds, new ReturnExecutionCallback<Integer>() {
			public Integer callback() {
				return jdbcHelper.queryForInt(extSQL, parameters.toArray(new Object[0]));
			}
		});
	}

	protected int doCountChangeLogGreaterThanId(DataEdgeDescriptor dataDesc, final long id) {
		DataSource ds = resolveJdbcDataSource();
		String descriptorClazzName = dataDesc == null ? "" : ClassUtils.getUserClass(dataDesc).getName();
		String descriptorIds = dataDesc == null ? "" : StringUtils.hasText(dataDesc.getId()) ? dataDesc.getId() : "";
		String splets[] = descriptorIds.split(";");
		JdbcTemplate jdbcHelper = new JdbcTemplate(ds);
		String extSQL = buildCountIdGtChangeLog(dataDesc.getDataIdentityPrefix(), splets.length);
		List<Object> parameters = new ArrayList<Object>(3 + splets.length);
		parameters.add(getNamespace());
		parameters.add(descriptorClazzName);
		parameters.addAll(Arrays.asList(splets));
		parameters.add(id);

		return doCountChangeLogGreaterThanIdOne(ds, jdbcHelper, extSQL, parameters);
		// int resultCount = doCountChangeLogGreaterThanIdOne(ds, jdbcHelper,
		// extSQL, descriptorClazzName, splets[0], id);
		// if (splets.length > 1) {
		// for (int i = 1; i < splets.length; i++) {
		// resultCount += doCountChangeLogGreaterThanIdOne(ds, jdbcHelper,
		// extSQL, descriptorClazzName, splets[i], id);
		// }
		// }
		// return resultCount;
	}

	private List<DataChangeLog> doGetChangeLogGreaterThanIdOne(final DataSource ds, final JdbcTemplate jdbcHelper,
			final String extSQL, final List<Object> params, final int from, final int count) {
		return DbUtils.executeInReadonly(ds, new ReturnExecutionCallback<List<DataChangeLog>>() {
			public List<DataChangeLog> callback() {
				return jdbcHelper.query(extSQL, params.toArray(new Object[0]),
						new ResultSetExtractor<List<DataChangeLog>>() {
							public List<DataChangeLog> extractData(ResultSet rs) throws SQLException,
									DataAccessException {
								if (from > 0)
									try {
										rs.absolute(from);
									} catch (SQLException e) {
										int i = 0;
										while (++i < from && rs.next())
											;
									}
								int readc = 0;
								List<DataChangeLog> list = new ArrayList<DataChangeLog>(count);
								while (rs.next() && (count < 0 || readc < count)) {
									list.add(DataChangeLogMapper.INST.mapRow(rs, readc++));
								}
								return list;
							}
						});
			}
		});
	}

	protected List<DataChangeLog> doGetChangeLogGreaterThanId(DataEdgeDescriptor dataDesc, long id, int from, int count) {
		DataSource ds = resolveJdbcDataSource();
		String descriptorClazzName = dataDesc == null ? "" : ClassUtils.getUserClass(dataDesc).getName();
		String descriptorIds = dataDesc == null ? "" : StringUtils.hasText(dataDesc.getId()) ? dataDesc.getId() : "";
		String splets[] = descriptorIds.split(";");
		JdbcTemplate jdbcHelper = new JdbcTemplate(ds);
		String extSQL = buildIdGtChangeLogSQL(dataDesc.getDataIdentityPrefix(), splets.length);
		List<Object> parameters = new ArrayList<Object>(3 + splets.length);
		parameters.add(getNamespace());
		parameters.add(descriptorClazzName);
		parameters.addAll(Arrays.asList(splets));
		parameters.add(id);
		return doGetChangeLogGreaterThanIdOne(ds, jdbcHelper, extSQL, parameters, from, count);
		// String countSQL = buildCountIdGtChangeLog();
		// List<DataChangeLog> resultList = new LinkedList<DataChangeLog>();
		// resultList.addAll(doGetChangeLogGreaterThanIdOne(ds, jdbcHelper,
		// extSQL, descriptorClazzName, splets[0], id, from, count));
		// if (splets.length > 1 && resultList.size() < count) {
		// for (int i = 1; i < splets.length && resultList.size() < count; i++)
		// {
		// int oldCount = doCountChangeLogGreaterThanIdOne(ds, jdbcHelper,
		// countSQL, descriptorClazzName, splets[i - 1], id);
		// from -= oldCount;
		// int newCount = count - resultList.size();
		// resultList.addAll(doGetChangeLogGreaterThanIdOne(ds, jdbcHelper,
		// extSQL, descriptorClazzName, splets[i], id, from, newCount));
		// }
		// }
		// return resultList;
	}

	public String saveChangeLogReturnLogId(DataEdgeDescriptor dataDesc, String sKey, DataAction action) {
		return Long.valueOf(doSaveChangeLog(dataDesc, sKey, action)).toString();
	}

	public Date saveChangeLogReturnRecordTime(DataEdgeDescriptor dataDesc, String sKey, DataAction action) {
		return doSaveChangeLogReturnRecordTime(dataDesc, sKey, action);
	}

	public void saveChangeLog(DataEdgeDescriptor dataDesc, String sKey, DataAction action) {
		doSaveChangeLogReturnRecordTime(dataDesc, sKey, action);
	}

	public String getLastChangeLogIdByDataIdentity(DataEdgeDescriptor dataDesc, String skey) {
		return Long.valueOf(doGetLastChangeLogId(dataDesc, skey)).toString();
	}

	public List<DataChangeLog> getChangeLogGreaterThanId(DataEdgeDescriptor dataDesc, String changeLogId, int from,
			int count) {
		return doGetChangeLogGreaterThanId(dataDesc, Long.parseLong(changeLogId), from, count);
	}

	public List<DataChangeLog> getChangeLogGreaterThanId(DataEdgeDescriptor dataDesc, String changeLogId) {
		return doGetChangeLogGreaterThanId(dataDesc, Long.parseLong(changeLogId));
	}

	public int countChangeLogGreaterThanId(DataEdgeDescriptor dataDesc, String changeLogId) {
		return doCountChangeLogGreaterThanId(dataDesc, Long.parseLong(changeLogId));
	}

	public DataChangeLog getLastChangeLog(DataEdgeDescriptor dataDesc) {
		return doGetLastChangeLog(dataDesc);
	}

	public void afterPropertiesSet() throws Exception {
		Assert.hasText(getCreateStorageJdbcSQLTemplate());
		Assert.hasText(getSaveLogJdbcSQLTemplate());
		Assert.hasText(getLastLogJdbcSQLTemplate());
		Assert.hasText(getIdEQChangeLogSQLTemplate());
		Assert.hasText(getIdGtChangeLogSQLTemplate());
	}

	protected static class DataChangeLogMapper implements RowMapper<DataChangeLog> {

		public static final RowMapper<DataChangeLog> INST = new DataChangeLogMapper();

		public DataChangeLog mapRow(ResultSet rs, int rowNum) throws SQLException {
			IdNumericDataChangeLog log = new IdNumericDataChangeLog();
			log.setRealId(rs.getLong("SID"));
			log.setNamespace(rs.getString("SCODE"));
			log.setDescriptorClassName(rs.getString("SDESC"));
			log.setDescriptorIdentity(rs.getString("DESCID"));
			log.setDataIdentity(rs.getString("SKEY"));
			log.setDataAction(DataAction.fromCode(rs.getShort("CTPE")));
			log.setRecordedTime(rs.getTimestamp("UPTM"));
			return log;
		}
	}

}
